/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include "GestureEventsViewComponentInstance.h"
#include <algorithm>
#include <arkui/ui_input_event.h>
#include <iostream>
#include <map>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

// 手势配置结构体
struct GestureConfig {
    std::string gestureType;
    int index;
    int minPointers;
    int minDistance;
    std::string direction;
    int numberOfTaps;
    int minDurationMs;
    int minVelocity;
    int minAngle;
    bool repeat;
};

// 常量定义：手指信息字段索引
enum FingerInfoIndex {
    FINGER_ID = 0,
    FINGER_X = 1,
    FINGER_Y = 2,
    FINGER_WINDOW_X = 3,
    FINGER_WINDOW_Y = 4,
    FINGER_DISPLAY_X = 5,
    FINGER_DISPLAY_Y = 6,
    FINGER_TILT_X = 7,
    FINGER_TILT_Y = 8,
    FINGER_TOTAL = 10,
    FINGER_INFO_COUNT = 9
};

// 常量定义：手势配置信息索引
enum GestureConfigIndex {
    GESTURE_TYPE = 0,
    GESTURE_INDEX = 1,
    GESTURE_MIN_POINTERS = 2,
    GESTURE_MIN_DISTANCE = 3,
    GESTURE_DIRECTION = 4,
    GESTURE_NUMBER_OF_TAPS = 5,
    GESTURE_MIN_DURATION_MS = 6,
    GESTURE_MIN_VELOCITY = 7,
    GESTURE_MIN_ANGLE = 8,
    GESTURE_REPEAT = 9,
    GESTURE_CONFIG_COUNT = 10
};
// 常量定义：手势参数默认值
enum GestureDefaultValue {
    MAX_POINTER = 5, // 旋转捏合手势最大手指数。
};

static const std::map<std::string, ArkUI_GestureDirection> DIRECTION_MAP = {
    {"all", GESTURE_DIRECTION_ALL},           {"horizontal", GESTURE_DIRECTION_HORIZONTAL},
    {"vertical", GESTURE_DIRECTION_VERTICAL}, {"left", GESTURE_DIRECTION_LEFT},
    {"right", GESTURE_DIRECTION_RIGHT},       {"up", GESTURE_DIRECTION_UP},
    {"down", GESTURE_DIRECTION_DOWN},         {"none", GESTURE_DIRECTION_NONE}};

static const std::map<std::string, ArkUI_GroupGestureMode> GROUP_GESTURE_MODE_MAP = {
    {"race", SEQUENTIAL_GROUP},           {"simultaneous", PARALLEL_GROUP},
    {"exclusive", EXCLUSIVE_GROUP}};

// 去除字符串两端空格
std::string Trim(const std::string &s)
{
    if (s.empty()) {
        return "";
    }
    
    auto start = s.begin();
    while (start != s.end() && std::isspace(*start)) {
        ++start;
    }

    auto end = s.end();
    do {
        --end;
    } while (std::distance(start, end) > 0 && std::isspace(*end));

    return std::string(start, end + 1);
}

// 按分隔符分割字符串
std::vector<std::string> Split(const std::string &str, char delimiter)
{
    if (str.empty()) {
        return {};
    }
    
    std::vector<std::string> tokens;
    std::stringstream ss(str);
    std::string token;
    while (std::getline(ss, token, delimiter)) {
        tokens.push_back(Trim(token));
    }
    return tokens;
}

// 解析方向表达式，返回 ArkUI_GestureDirectionMask（uint32_t）
ArkUI_GestureDirectionMask ParseDirection(const std::string &m_direction,
                                          const std::map<std::string, ArkUI_GestureDirection> &directionMap)
{
    if (m_direction.empty()) {
        return GESTURE_DIRECTION_ALL;
    }
    
    if (m_direction.find('&') == std::string::npos && m_direction.find('|') == std::string::npos) {
        auto key = Trim(m_direction);
        auto it = directionMap.find(key);
        if (it != directionMap.end()) {
            return static_cast<ArkUI_GestureDirectionMask>(it->second);
        }
        return static_cast<ArkUI_GestureDirectionMask>(GESTURE_DIRECTION_ALL);
    }

    char op = '&';
    if (m_direction.find('|') != std::string::npos) {
        op = '|';
    }

    std::vector<std::string> parts = Split(m_direction, op);

    ArkUI_GestureDirectionMask result = 0;
    bool first = true;

    for (const auto &part : parts) {
        auto key = part;
        auto it = directionMap.find(key);
        if (it == directionMap.end()) {
            continue;
        }

        auto value = static_cast<ArkUI_GestureDirectionMask>(it->second);

        if (first) {
            result = value;
            first = false;
        } else {
            result = (op == '&') ? (result & value) : (result | value);
        }
    }

    return first ? static_cast<ArkUI_GestureDirectionMask>(GESTURE_DIRECTION_NONE) : result;
}

// 解析单个手势配置字符串
GestureConfig ParseSingleGestureConfig(const std::string& multiGestures)
{
    std::vector<std::string> fields = Split(multiGestures, ',');
    if (fields.size() != GESTURE_CONFIG_COUNT) {
        throw std::invalid_argument("Invalid gesture config format");
    }

    GestureConfig config;
    config.gestureType = fields[GESTURE_TYPE];
    config.index = std::stoi(fields[GESTURE_INDEX]);
    config.minPointers = std::stoi(fields[GESTURE_MIN_POINTERS]);
    config.minDistance = std::stoi(fields[GESTURE_MIN_DISTANCE]);
    config.direction = fields[GESTURE_DIRECTION];
    config.numberOfTaps = std::stoi(fields[GESTURE_NUMBER_OF_TAPS]);
    config.minDurationMs = std::stoi(fields[GESTURE_MIN_DURATION_MS]);
    config.minVelocity = std::stoi(fields[GESTURE_MIN_VELOCITY]);
    config.minAngle = std::stoi(fields[GESTURE_MIN_ANGLE]);
    config.repeat = (fields[GESTURE_REPEAT] == "true");

    return config;
}

namespace rnoh {
void GestureEventsViewComponentInstance::ReceiveEventStatic(ArkUI_NodeEvent *event)
{
    void *userData = OH_ArkUI_NodeEvent_GetUserData(event);
    if (userData) {
        auto instance = static_cast<GestureEventsViewComponentInstance *>(userData);
        instance->ReceiveEvent(event);
    }
}

void GestureEventsViewComponentInstance::ReceiveEvent(ArkUI_NodeEvent *event)
{
    try {
        auto eventType = OH_ArkUI_NodeEvent_GetEventType(event);
        if (eventType == NODE_ON_HOVER_EVENT) {
            ArkUI_UIInputEvent *inputEvent = OH_ArkUI_NodeEvent_GetInputEvent(event);
            bool isHover = OH_ArkUI_HoverEvent_IsHovered(inputEvent);
            this->OnHover(isHover, m_hoverGestureType);
        }
    } catch (std::exception &e) {
        LOG(ERROR) << e.what();
    }
}

GestureEventsViewComponentInstance::GestureEventsViewComponentInstance(Context context) : Super(std::move(context))
{
    m_stackNode.setStackNodeDelegate(this);
}

StackNode &GestureEventsViewComponentInstance::getLocalRootArkUINode() { return m_stackNode; }

bool GestureEventsViewComponentInstance::GetRepeat() { return m_repeat; }

std::unordered_map<std::string, ArkUI_GestureRecognizer*> GestureEventsViewComponentInstance::gestureMap;

void GestureEventsViewComponentInstance::onPropsChanged(SharedConcreteProps const &props)
{
    UpdateGestureProperties(props);
    auto gestureApi = reinterpret_cast<ArkUI_NativeGestureAPI_1 *>(
        OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_GESTURE, "ArkUI_NativeGestureAPI_1"));
    
    ArkUI_GestureRecognizer *gesture = CreateGestureRecognizer(gestureApi);
    if (m_gestureType == "hover" || gesture == nullptr) {
        // 悬浮事件，createGestureRecognizer返回的是nullptr, 在这里直接返回。
        return;
    }
    auto uniqueIdItem = NativeNodeApi::getInstance()->getAttribute(m_stackNode.getArkUINodeHandle(), NODE_UNIQUE_ID);
    std::string nodeId = "";
    if (uniqueIdItem) {
        nodeId = std::to_string(uniqueIdItem->value->i32);
    }
    std::string key = nodeId + "_" + m_gestureType;
    auto it = gestureMap.find(key);
    if (it != gestureMap.end() && it->second != nullptr) {
        gestureApi->removeGestureFromNode(m_stackNode.getArkUINodeHandle(), it->second);
        LOG(INFO) << "Removed existing gesture for type: " << key;
    }
    gestureMap[key] = gesture;
    gestureApi->addGestureToNode(m_stackNode.getArkUINodeHandle(), gesture, PRIORITY, NORMAL_GESTURE_MASK);
}

void GestureEventsViewComponentInstance::UpdateGestureProperties(SharedConcreteProps const &props)
{
    m_fingers = props->fingers ? props->fingers : m_fingers;
    m_direction = !props->direction.empty() ? props->direction : m_direction;
    m_minDistance = props->minDistance ? props->minDistance : m_minDistance;
    m_gestureType = !props->gestureType.empty() ? props->gestureType : m_gestureType;
    m_numberOfTaps = props->numberOfTaps ? props->numberOfTaps : m_numberOfTaps;
    m_minDurationMs = props->minDurationMs ? props->minDurationMs : m_minDurationMs;
    m_minAngle = props->minAngle ? props->minAngle : m_minAngle;
    m_repeat = props->repeat;
    m_multiGestureType = !props->multiGestureType.empty() ? props->multiGestureType : m_multiGestureType;
    m_isMultiGesture = props->isMultiGesture ? props->isMultiGesture : m_isMultiGesture;
    m_multiGestures = !props->multiGestures.empty() ? props->multiGestures : m_multiGestures;
}

ArkUI_GestureRecognizer* GestureEventsViewComponentInstance::CreateGestureCreators(
    ArkUI_NativeGestureAPI_1* gestureApi, const std::string& multiGestures)
{
    try {
        GestureConfig config = ParseSingleGestureConfig(multiGestures);
        if (config.gestureType == "pan") {
            return gestureApi->createPanGesture(
                config.minPointers,
                ParseDirection(config.direction, DIRECTION_MAP),
                config.minDistance);
        } else if (config.gestureType == "tap") {
            return gestureApi->createTapGesture(config.numberOfTaps, config.minPointers);
        } else if (config.gestureType == "longPress") {
            return gestureApi->createLongPressGesture(
                config.minPointers,
                config.repeat,
                config.minDurationMs);
        } else if (config.gestureType == "pinch") {
            return gestureApi->createPinchGesture(
                config.minPointers > MAX_POINTER ? MAX_POINTER : config.minPointers,
                config.minDistance);
        } else if (config.gestureType == "rotation") {
            return gestureApi->createRotationGesture(
                config.minPointers > MAX_POINTER ? MAX_POINTER : config.minPointers,
                config.minAngle);
        } else if (config.gestureType == "fling") {
            return gestureApi->createSwipeGesture(
                config.minPointers,
                ParseDirection(config.direction, DIRECTION_MAP),
                config.minVelocity);
        } else if (config.gestureType == "hover") {
            m_hoverGestureType = std::to_string(config.index);
            NativeNodeApi::getInstance()->registerNodeEvent(m_stackNode.getArkUINodeHandle(), NODE_ON_HOVER_EVENT,
                                                            NODE_ON_HOVER_EVENT, this);
            NativeNodeApi::getInstance()->addNodeEventReceiver(m_stackNode.getArkUINodeHandle(),
                                                               &GestureEventsViewComponentInstance::ReceiveEventStatic);
            return nullptr;
        } else {
            throw std::invalid_argument("Unknown gesture type: " + config.gestureType);
        }
    } catch (const std::exception& e) {
        LOG(ERROR) << "Error creating gesture: " << e.what();
        return nullptr;
    }
}

ArkUI_GestureRecognizer* GestureEventsViewComponentInstance::CreateGestureRecognizer(
    ArkUI_NativeGestureAPI_1* gestureApi)
{
    if (!m_isMultiGesture) {
        // 拼接成员变量为 multiGestures 字符串
        std::string multiGestures =
            m_gestureType + "," +
            std::to_string(m_index) + "," +
            std::to_string(m_fingers) + "," +
            std::to_string(m_minDistance) + "," +
            m_direction + "," +
            std::to_string(m_numberOfTaps) + "," +
            std::to_string(m_minDurationMs) + "," +
            std::to_string(m_minVelocity) + "," +
            std::to_string(m_minAngle) + "," +
            (GetRepeat() ? "true" : "false");
        ArkUI_GestureRecognizer* gesture = CreateGestureCreators(gestureApi, multiGestures);
        if (m_gestureType == "hover") {
            return nullptr;
        }
        if (gesture) {
            SetupGestureCallbacks(gestureApi, gesture, m_gestureType);
        }
        return gesture;
    } else {
        auto groupGesture = gestureApi->createGroupGesture(GROUP_GESTURE_MODE_MAP.at(m_multiGestureType));
        for (const auto& multiGestures : m_multiGestures) {
            GestureConfig config = ParseSingleGestureConfig(multiGestures);
            ArkUI_GestureRecognizer* subGesture = CreateGestureCreators(gestureApi, multiGestures);
            if (config.gestureType == "hover") {
                continue;
            }
            if (subGesture) {
                SetupGestureCallbacks(gestureApi, subGesture, std::to_string(config.index));
                gestureApi->addChildGesture(groupGesture, subGesture);
            }
        }
        return groupGesture;
    }
}

struct GestureCallbackContext {
    GestureEventsViewComponentInstance* instance;
    std::string gestureType;
};

void GestureEventsViewComponentInstance::SetupGestureCallbacks(
    ArkUI_NativeGestureAPI_1 *gestureApi, ArkUI_GestureRecognizer *gesture, std::string gestureType)
{
    auto onActionCallBack = [](ArkUI_GestureEvent *event, void *extraParam) {
        auto context = static_cast<GestureCallbackContext*>(extraParam);
        switch (OH_ArkUI_GestureEvent_GetActionType(event)) {
            case GESTURE_EVENT_ACTION_ACCEPT: {
                context->instance->OnGestureStart(event, context->gestureType);
                break;
            }
            case GESTURE_EVENT_ACTION_UPDATE: {
                context->instance->OnGestureUpdate(event, context->gestureType);
                break;
            }
            case GESTURE_EVENT_ACTION_END: {
                context->instance->OnGestureEnd(event, context->gestureType);
                break;
            }
            case GESTURE_EVENT_ACTION_CANCEL: {
                context->instance->OnGestureCancel(event, context->gestureType);
                break;
            }
        }
    };
    
    // 动态分配上下文
    auto context = new GestureCallbackContext();
    context->instance = this;
    context->gestureType = std::move(gestureType);
    
    constexpr auto gestureEventMask = GESTURE_EVENT_ACTION_ACCEPT | GESTURE_EVENT_ACTION_UPDATE |
                                      GESTURE_EVENT_ACTION_END | GESTURE_EVENT_ACTION_CANCEL;
    gestureApi->setGestureEventTarget(gesture, gestureEventMask, context, onActionCallBack);
}

void GestureEventsViewComponentInstance::onChildInserted(ComponentInstance::Shared const &childComponentInstance,
                                                         std::size_t index)
{
    CppComponentInstance::onChildInserted(childComponentInstance, index);
    m_stackNode.insertChild(childComponentInstance->getLocalRootArkUINode(), index);
}

void GestureEventsViewComponentInstance::onChildRemoved(ComponentInstance::Shared const &childComponentInstance)
{
    CppComponentInstance::onChildRemoved(childComponentInstance);
    m_stackNode.removeChild(childComponentInstance->getLocalRootArkUINode());
}

std::vector<std::vector<Float>> GestureEventsViewComponentInstance::GetFingerList(ArkUI_GestureEvent *event)
{
    std::vector<std::vector<Float>> fingerList;
    auto uiInputEvent = OH_ArkUI_GestureEvent_GetRawInputEvent(event);
    // 依次获取每个手指的信息，最多10个。
    for (int i = 0; i < FINGER_TOTAL; i++) {
        // 将手指信息依次填入到一个列表中。
        std::vector<Float> fingerInfo(FINGER_INFO_COUNT);
        fingerInfo[FINGER_ID] = OH_ArkUI_PointerEvent_GetPointerId(uiInputEvent, i);
        fingerInfo[FINGER_X] = OH_ArkUI_PointerEvent_GetXByIndex(uiInputEvent, i);
        fingerInfo[FINGER_Y] = OH_ArkUI_PointerEvent_GetYByIndex(uiInputEvent, i);
        fingerInfo[FINGER_WINDOW_X] = OH_ArkUI_PointerEvent_GetWindowXByIndex(uiInputEvent, i);
        fingerInfo[FINGER_WINDOW_Y] = OH_ArkUI_PointerEvent_GetWindowYByIndex(uiInputEvent, i);
        fingerInfo[FINGER_DISPLAY_X] = OH_ArkUI_PointerEvent_GetDisplayXByIndex(uiInputEvent, i);
        fingerInfo[FINGER_DISPLAY_Y] = OH_ArkUI_PointerEvent_GetDisplayYByIndex(uiInputEvent, i);
        fingerInfo[FINGER_TILT_X] = OH_ArkUI_PointerEvent_GetTiltX(uiInputEvent, i);
        fingerInfo[FINGER_TILT_Y] = OH_ArkUI_PointerEvent_GetTiltY(uiInputEvent, i);

        bool allZero = true;
        for (const auto &val : fingerInfo) {
            if (val != 0) {
                allZero = false;
                break;
            }
        }

        if (allZero) {
            break;
        } else {
            fingerList.push_back(fingerInfo);
        }
    }
    return fingerList;
}

template <typename T>
void FillCommonGestureFields(
    T &gEvent, ArkUI_GestureEvent *event, GestureEventsViewComponentInstance *instance, std::string gestureType)
{
    gEvent.type = gestureType;
    gEvent.repeat = instance->GetRepeat();
    gEvent.offsetX = OH_ArkUI_PanGesture_GetOffsetX(event);
    gEvent.offsetY = OH_ArkUI_PanGesture_GetOffsetY(event);
    gEvent.angle = OH_ArkUI_RotationGesture_GetAngle(event);
    gEvent.scale = OH_ArkUI_PinchGesture_GetScale(event);
    gEvent.pinchCenterX = OH_ArkUI_PinchGesture_GetCenterX(event);
    gEvent.pinchCenterY = OH_ArkUI_PinchGesture_GetCenterY(event);
    gEvent.speed = OH_ArkUI_SwipeGesture_GetVelocity(event);
    gEvent.fingerList = instance->GetFingerList(event);
    gEvent.velocityX = OH_ArkUI_PanGesture_GetVelocityX(event);
    gEvent.velocityY = OH_ArkUI_PanGesture_GetVelocityY(event);
    gEvent.velocity = OH_ArkUI_PanGesture_GetVelocity(event);

    auto uiInputEvent = OH_ArkUI_GestureEvent_GetRawInputEvent(event);
    gEvent.timestamp = OH_ArkUI_UIInputEvent_GetEventTime(uiInputEvent);
    gEvent.source = OH_ArkUI_UIInputEvent_GetSourceType(uiInputEvent);
    gEvent.rollAngle = 0; // 手写笔与设备平面的夹角，暂无CAPI
    gEvent.sourceTool = OH_ArkUI_UIInputEvent_GetToolType(uiInputEvent);
    gEvent.axisHorizontal = OH_ArkUI_AxisEvent_GetHorizontalAxisValue(uiInputEvent);
    gEvent.axisVertical = OH_ArkUI_AxisEvent_GetVerticalAxisValue(uiInputEvent);
    gEvent.deviceId = OH_ArkUI_UIInputEvent_GetDeviceId(uiInputEvent);
    gEvent.targetDisplayId = OH_ArkUI_UIInputEvent_GetTargetDisplayId(uiInputEvent);
}

void GestureEventsViewComponentInstance::OnGestureStart(ArkUI_GestureEvent *event, std::string gestureType)
{
    facebook::react::GestureEventsViewEventEmitter::OnGestureStart gEvent;
    FillCommonGestureFields(gEvent, event, this, gestureType);
    m_eventEmitter->onGestureStart(gEvent);
}

void GestureEventsViewComponentInstance::OnGestureUpdate(ArkUI_GestureEvent *event, std::string gestureType)
{
    facebook::react::GestureEventsViewEventEmitter::OnGestureUpdate gEvent;
    FillCommonGestureFields(gEvent, event, this, gestureType);
    m_eventEmitter->onGestureUpdate(gEvent);
}

void GestureEventsViewComponentInstance::OnGestureEnd(ArkUI_GestureEvent *event, std::string gestureType)
{
    facebook::react::GestureEventsViewEventEmitter::OnGestureEnd gEvent;
    FillCommonGestureFields(gEvent, event, this, gestureType);
    m_eventEmitter->onGestureEnd(gEvent);
}

void GestureEventsViewComponentInstance::OnGestureCancel(ArkUI_GestureEvent *event, std::string gestureType)
{
    facebook::react::GestureEventsViewEventEmitter::OnGestureCancel gEvent;
    FillCommonGestureFields(gEvent, event, this, gestureType);
    m_eventEmitter->onGestureCancel(gEvent);
}

void GestureEventsViewComponentInstance::OnHover(bool isHover, std::string gestureType)
{
    facebook::react::GestureEventsViewEventEmitter::OnHover gEvent;
    gEvent.isHover = isHover;
    gEvent.type = gestureType;
    m_eventEmitter->onHover(gEvent);
}
} // namespace rnoh
